package com.lxs.mall.service.Impl;

import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.google.zxing.WriterException;
import com.lxs.mall.common.Constant;
import com.lxs.mall.exception.LxsMallException;
import com.lxs.mall.exception.LxsMallExceptionEnum;
import com.lxs.mall.filter.UserFilter;
import com.lxs.mall.model.dao.CartMapper;
import com.lxs.mall.model.dao.OrderItemMapper;
import com.lxs.mall.model.dao.OrderMapper;
import com.lxs.mall.model.dao.ProductMapper;
import com.lxs.mall.model.pojo.Order;
import com.lxs.mall.model.pojo.OrderItem;
import com.lxs.mall.model.pojo.Product;
import com.lxs.mall.model.query.OrderStatisticsQuery;
import com.lxs.mall.model.request.CreateOrderReq;
import com.lxs.mall.model.vo.CartVo;
import com.lxs.mall.model.vo.OrderItemVo;
import com.lxs.mall.model.vo.OrderStatisticsVo;
import com.lxs.mall.model.vo.OrderVo;
import com.lxs.mall.service.CartService;
import com.lxs.mall.service.OrderService;
import com.lxs.mall.service.UserService;
import com.lxs.mall.util.OrderCodeFactory;
import com.lxs.mall.util.QRCodeGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 小松
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    OrderMapper orderMapper;
    @Resource
    OrderItemMapper orderItemMapper;
    @Resource
    CartService cartService;
    @Resource
    CartMapper cartMapper;
    @Resource
    ProductMapper productMapper;
    @Resource
    UserService userService;

    @Value("${file.upload.uri}")
    String uri;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String create(CreateOrderReq createOrderReq) {
        //拿到用户ID
        Integer userId = UserFilter.userThreadLocal.get().getId();
        //从购物车查找已经勾选的商品
        List<CartVo> cartVoList = cartService.list(userId);
        ArrayList<CartVo> cartVoArrayList = new ArrayList<>();
        for (CartVo cartVO : cartVoList) {
            if (cartVO.getSelected().equals(Constant.CartSelected.CHECKED)) {
                cartVoArrayList.add(cartVO);
            }
        }
        cartVoList = cartVoArrayList;
        //如果购物车已勾选的为空，报错
        if (CollectionUtils.isEmpty(cartVoList)) {
            throw new LxsMallException(LxsMallExceptionEnum.CART_ENOUGH);
        }
        //判断商品是否存在、上下架状态、库存
        validSaleStatusAndStock(cartVoList);
        //把购物车对象转为订单item对象
        List<OrderItem> orderItemList = cartVoListToOrderItemList(cartVoList);
        //扣库存
        for (OrderItem orderItem : orderItemList) {
            Product product = productMapper.selectByPrimaryKey(orderItem.getProductId());
            int stock = product.getStock() - orderItem.getQuantity();
            if (stock < 0) {
                throw new LxsMallException(LxsMallExceptionEnum.CART_ENOUGH);
            }
            product.setStock(stock);
            productMapper.updateByPrimaryKeySelective(product);
        }
        //把购物车中的已勾选商品删除
        cleanCart(cartVoList);
        //生成订单
        Order order = new Order();
        //生成订单号，有独立的规则
        String orderNo = OrderCodeFactory.getOrderCode(userId);
        order.setOrderNo(orderNo);
        order.setUserId(userId);
        order.setReceiverName(createOrderReq.getReceiverName());
        order.setReceiverMobile(createOrderReq.getReceiverMobile());
        order.setReceiverAddress(createOrderReq.getReceiverAddress());
        order.setTotalPrice(totalPrice(orderItemList));
        order.setOrderStatus(Constant.OrderStatusEnum.NON_PAYMENT.getCode());
        order.setPostage(0);
        order.setPaymentType(1);
        orderMapper.insertSelective(order);
        //循环保存每个商品到order_ item表
        for (OrderItem orderItem : orderItemList) {
            orderItem.setOrderNo(order.getOrderNo());
            orderItemMapper.insertSelective(orderItem);
        }
        //把结果返回
        return orderNo;
    }

    private Integer totalPrice(List<OrderItem> orderItemList) {
        Integer total = 0;
        for (OrderItem orderItem : orderItemList) {
            total += orderItem.getTotalPrice();
        }
        return total;
    }

    private void cleanCart(List<CartVo> cartVoList) {
        for (CartVo cartVO : cartVoList) {
            cartMapper.deleteByPrimaryKey(cartVO.getId());
        }
    }

    private List<OrderItem> cartVoListToOrderItemList(List<CartVo> cartVoList) {
        List<OrderItem> orderItemList = new ArrayList<>();
        for (CartVo cartvo : cartVoList) {
            OrderItem orderItem = new OrderItem();
            orderItem.setProductId(cartvo.getProductId());
            //快照
            orderItem.setProductName(cartvo.getProductName());
            orderItem.setProductImg(cartvo.getProductImage());
            orderItem.setQuantity(cartvo.getQuantity());
            orderItem.setUnitPrice(cartvo.getPrice());
            orderItem.setTotalPrice(cartvo.getTotalPrice());
            orderItemList.add(orderItem);
        }
        return orderItemList;
    }

    private void validSaleStatusAndStock(List<CartVo> cartVoList) {
        for (CartVo vo : cartVoList) {
            Product product = productMapper.selectByPrimaryKey(vo.getProductId());
            //判断商品是否存在，商品是否上架
            if (product == null || product.getStatus().equals(Constant.SellStatus.NOT_SELL)) {
                throw new LxsMallException(LxsMallExceptionEnum.NOT_SELL);
            }
            //判断商品库存
            if (vo.getQuantity() > product.getStock()) {
                throw new LxsMallException(LxsMallExceptionEnum.NOT_ENOUGH);
            }
        }
    }

    @Override
    public OrderVo detail(String orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        //订单不存在
        if (order == null) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_ORDER);
        }
        //如果订单不存在，则需要判断所属
        Integer userId = UserFilter.userThreadLocal.get().getId();
        if (!userId.equals(order.getUserId())) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_YOUR_ORDER);
        }
        return getOrderVo(order);
    }

    private OrderVo getOrderVo(Order order) {
        OrderVo orderVO = new OrderVo();
        BeanUtils.copyProperties(order, orderVO);
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderNo(order.getOrderNo());
        List<OrderItemVo> orderItemVoList = new ArrayList<>();
        for (OrderItem orderItem : orderItemList) {
            OrderItemVo orderItemVO = new OrderItemVo();
            BeanUtils.copyProperties(orderItem, orderItemVO);
            orderItemVoList.add(orderItemVO);
        }
        orderVO.setOrderItemVOList(orderItemVoList);
        orderVO.setOrderStatusName(Constant.OrderStatusEnum.codeOf(orderVO.getOrderStatus()).getValue());
        return orderVO;
    }

    @Override
    public PageInfo<OrderVo> listForCustomer(Integer pageNum, Integer pageSize) {
        PageMethod.startPage(pageNum, pageSize);
        Integer userId = UserFilter.currentUser.getId();
        List<Order> orderList = orderMapper.selectForCustomer(userId);
        List<OrderVo> orderVoList = orderListToOrderVOList(orderList);
        PageInfo<OrderVo> pageInfo = new PageInfo<>(orderVoList);
        pageInfo.setList(orderVoList);
        return pageInfo;
    }

    private List<OrderVo> orderListToOrderVOList(List<Order> orderList) {
        List<OrderVo> orderVoList = new ArrayList<>();
        for (Order order : orderList) {
            OrderVo orderVO = getOrderVo(order);
            orderVoList.add(orderVO);
        }
        return orderVoList;
    }

    @Override
    public void cancel(String orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_ORDER);
        }
        Integer userId = UserFilter.currentUser.getId();
        if (!order.getUserId().equals(userId)) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_YOUR_ORDER);
        }
        if (order.getOrderStatus().equals(Constant.OrderStatusEnum.NON_PAYMENT.getCode())) {
            order.setOrderStatus(Constant.OrderStatusEnum.CANCELED.getCode());
            order.setEndTime(new Date());
            orderMapper.updateByPrimaryKeySelective(order);
        } else {
            throw new LxsMallException(LxsMallExceptionEnum.CANCEL_WRONG_ORDER_STATUS);
        }
    }

    @Override
    public String qrcode(String orderNo) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        assert servletRequestAttributes != null;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String address = uri;
        String payUrl = "http://" + address + "/pay?orderNo=" + orderNo;
        try {
            QRCodeGenerator.generateQRCodeImage(payUrl, 350, 350,
                    Constant.FILE_UPLOAD_DIR + orderNo + ".png");
        } catch (WriterException | IOException e) {
            e.printStackTrace();
        }
        return "http://" + address + "/images/" + orderNo + ".png";
    }

    @Override
    public PageInfo<OrderVo> listForAdmin(Integer pageNum, Integer pageSize) {
        PageMethod.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.selectForAdmin();
        List<OrderVo> orderVoList = orderListToOrderVOList(orderList);
        PageInfo<OrderVo> pageInfo = new PageInfo<>(orderVoList);
        pageInfo.setList(orderVoList);
        return pageInfo;
    }

    @Override
    public void pay(String orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_ORDER);
        }
        if (order.getOrderStatus().equals(Constant.OrderStatusEnum.NON_PAYMENT.getCode())) {
            order.setOrderStatus(Constant.OrderStatusEnum.ACCOUNT_PAID.getCode());
            order.setPayTime(new Date());
            orderMapper.updateByPrimaryKeySelective(order);
        } else {
            throw new LxsMallException(LxsMallExceptionEnum.PAY_WRONG_ORDER_STATUS);
        }
    }

    @Override
    public void delivered(String orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_ORDER);
        }
        if (order.getOrderStatus().equals(Constant.OrderStatusEnum.ACCOUNT_PAID.getCode())) {
            order.setOrderStatus(Constant.OrderStatusEnum.DELIVERED.getCode());
            order.setDeliveryTime(new Date());
            orderMapper.updateByPrimaryKeySelective(order);
        } else {
            throw new LxsMallException(LxsMallExceptionEnum.DELIVER_WRONG_ORDER_STATUS);
        }
    }

    @Override
    public void finish(String orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_ORDER);
        }
        //如果是普通用户，就要校验订单的所属
        if (!userService.checkAdmin(UserFilter.currentUser) && order.getUserId()
                .equals(UserFilter.currentUser.getId())) {
            throw new LxsMallException(LxsMallExceptionEnum.NO_YOUR_ORDER);
        }
        //发货后可以完结订单
        if (order.getOrderStatus().equals(Constant.OrderStatusEnum.DELIVERED.getCode())) {
            order.setOrderStatus(Constant.OrderStatusEnum.COMPLETEnterACTION.getCode());
            order.setEndTime(new Date());
            orderMapper.updateByPrimaryKeySelective(order);
        } else {
            throw new LxsMallException(LxsMallExceptionEnum.FINISH_WRONG_ORDER_STATUS);
        }
    }
    @Override
    public List<OrderStatisticsVo> statistics(Date startDate, Date endDate){
        OrderStatisticsQuery orderStatisticsQuery = new OrderStatisticsQuery();
        orderStatisticsQuery.setStartDate(startDate);
        orderStatisticsQuery.setEndDate(endDate);
        List<OrderStatisticsVo> orderStatisticsVoList = orderMapper.selectOrderStatistics(orderStatisticsQuery);
        return orderStatisticsVoList;
    }
}
